package com.bruce.learnrecycler.kotlin.ui.custom

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import android.view.animation.DecelerateInterpolator
import com.bruce.learnrecylerview.app.R

/**
 * Created by wangzhijie@wind-mobi.com on 2015/9/11.
 */
public class TwoBallLoadingView: View {
    public constructor(context: Context) : super(context) {
        configureAnimator()
    }

    public constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.TwoBallLoadingView)
        val color1 = ta.getString(R.styleable.TwoBallLoadingView_color1)
        val color2 = ta.getString(R.styleable.TwoBallLoadingView_color2)
        if (!TextUtils.isEmpty(color1)) {
            ball1.color = Color.parseColor(color1)
        }
        if (!TextUtils.isEmpty(color2)) {
            ball2.color = Color.parseColor(color2)
        }

        maxRadius = ta.getInteger(R.styleable.TwoBallLoadingView_maxRadius, DEFAULT_MAX_RADIUS)
        minRadius = ta.getInteger(R.styleable.TwoBallLoadingView_minRadius, DEFAULT_MIN_RADIUS)
        range = ta.getInteger(R.styleable.TwoBallLoadingView_range, DEFAULT_RANGE)
        duration = ta.getInteger(R.styleable.TwoBallLoadingView_duration, DEFAULT_ANIMATION_DURATION)
        configureAnimator()
    }

    public constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        configureAnimator()
    }


    val DEFAULT_MAX_RADIUS = 15
    val DEFAULT_MIN_RADIUS = 5
    val DEFAULT_RANGE = 20
    val DEFAULT_BALL_1_COLOR = Color.parseColor("#40df73")
    val DEFAULT_BALL_2_COLOR = Color.parseColor("#ffdf3e")
    val DEFAULT_ANIMATION_DURATION = 1000
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)


    var maxRadius = DEFAULT_MAX_RADIUS
    var minRadius = DEFAULT_MIN_RADIUS
    var range = DEFAULT_RANGE
    var duration = DEFAULT_ANIMATION_DURATION

    val ball1 = Ball(DEFAULT_BALL_1_COLOR)
    val ball2 = Ball(DEFAULT_BALL_2_COLOR)

    var centerX = 0f
    var centerY = 0f

    var animatorSet:AnimatorSet? = null

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        centerX = w / 2f
        centerY = h / 2f
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(handleWidthMeasure(widthMeasureSpec), handleHeightMeasure(heightMeasureSpec))
        centerX = getWidth() / 2f
        centerY = getHeight() / 2f
    }

    private fun handleWidthMeasure(spec: Int): Int {
        return View.MeasureSpec.getSize(spec)
    }

    private fun handleHeightMeasure(spec: Int): Int {
        var result = 0
        val mode = View.MeasureSpec.getMode(spec)
        val size = View.MeasureSpec.getSize(spec)
        when(mode) {
            View.MeasureSpec.AT_MOST -> result = size
            View.MeasureSpec.EXACTLY -> result = Math.min(size, maxRadius * 3)
            View.MeasureSpec.UNSPECIFIED -> result = maxRadius * 3
        }
        return result
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val balls = if (ball1.radius < ball2.radius) listOf(ball1, ball2) else listOf(ball2, ball1)
        balls forEach {
            paint.setColor(it.color)
            canvas.drawCircle(it.centerX, centerY, it.radius, paint)
        }
    }

    fun configureAnimator() {
        val centerRadius = (maxRadius + minRadius) / 2f

        val scaleAnimator1 = ObjectAnimator.ofFloat(ball1, "radius", centerRadius, maxRadius.toFloat(), centerRadius, minRadius.toFloat(), centerRadius)
        scaleAnimator1 setRepeatCount ValueAnimator.INFINITE

        val centerAnimator1 = ValueAnimator.ofFloat(-1f, 0f, 1f ,0f, -1f)
        centerAnimator1 setRepeatCount ValueAnimator.INFINITE
        centerAnimator1 addUpdateListener {
            val value = it.getAnimatedValue() as Float
            val x = centerX + range * value
            ball1.centerX = x
            invalidate()
        }

        val scaleAnimator2 = ObjectAnimator.ofFloat(ball2, "radius", centerRadius, minRadius.toFloat(), centerRadius, maxRadius.toFloat(), centerRadius)
        scaleAnimator2 setRepeatCount ValueAnimator.INFINITE

        val centerAnimator2 = ValueAnimator.ofFloat(1f, 0f, -1f ,0f, 1f)
        centerAnimator2 setRepeatCount ValueAnimator.INFINITE
        centerAnimator2 addUpdateListener {
            val value = it.getAnimatedValue() as Float
            val x = centerX + range * value
            ball2.centerX = x
        }
        animatorSet = AnimatorSet()
        animatorSet!!.playTogether(scaleAnimator1, centerAnimator1,scaleAnimator2, centerAnimator2)
        animatorSet!!.setDuration(DEFAULT_ANIMATION_DURATION.toLong())
        animatorSet!!.setInterpolator(DecelerateInterpolator());
    }

    fun startAnimation() {
        if (getVisibility() != View.VISIBLE || animatorSet?.isRunning()?:false) return
        animatorSet?.start()
    }
    fun stopAnimation() {
        animatorSet?.end()
    }

    override fun setVisibility(visibility: Int) {
        if (getVisibility() == visibility) return
        super.setVisibility(visibility)
        if (isShown()) {
            startAnimation()
        } else {
            stopAnimation()
        }
    }

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        if (isShown()) {
            startAnimation()
        } else {
            stopAnimation()
        }
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        startAnimation()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        stopAnimation()
    }
}

data class Ball(var color:Int,var radius:Float = 0f, var centerX:Float = 0f) {}